前端那些事

vuePress-theme-reco chenpeng    2020 - 2021
前端那些事 前端那些事

Choose mode

  • dark
  • auto
  • light
首页
文章目录
  • Browser
  • CSS
  • ES6
  • JavaScript
  • Network
  • TypeScript
  • Vue
  • Vue3
  • Webpack
标签
时间轴
GitHub
author-avatar

chenpeng

85

Article

25

Tag

首页
文章目录
  • Browser
  • CSS
  • ES6
  • JavaScript
  • Network
  • TypeScript
  • Vue
  • Vue3
  • Webpack
标签
时间轴
GitHub
  • ES6-API

    • Proxy
    • Reflect

Proxy

vuePress-theme-reco chenpeng    2020 - 2021

Proxy

chenpeng 2020-11-30 ES6 API

# 1.概念

Proxy 意为代理,在目标对象之前设置一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,对外界的访问可以进行过滤和改写

# 2.声明 Proxy

let proxy = new Proxy(target, handler);
1

Proxy 构造函数中有两个参数:

  1. target:使用 Proxy 包装的代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
  2. handler:也是一个对象,用来定制拦截行为

# 3.Proxy 中的处理方法

方法 描述
get 获取某个 key 值
set 设置某个 key 值
has 使用 in 操作符判断某个 key 是否存在
apply 函数调用,仅在代理对象为 function 时有效
ownKeys 获取目标对象所有的 key
construct 函数通过实例化调用,仅在代理对象为 function 时有效
isExtensible 判断对象是否可扩展,Object.isExtensible 的代理
deleteProperty 删除一个 property
defineProperty 定义一个新的 property
getPrototypeOf 获取原型对象
setPrototypeOf 设置原型对象
preventExtensions 设置对象为不可扩展
getOwnPropertyDescriptor 获取一个自有属性(不会去原型链查找)的属性描述

get() 方法

get() 方法用于获取某对象属性值时的预处理,接受两个常用参数:

  1. target:目标对象
  2. key:被获取的属性名

示例:

const person = {
    firstName: 'zhang',
    lastName: 'san',
};
let handler = {
    get(target, key){
        if(key === 'fullName'){
            return `${target.firstName} ${target.lastName}`
        }
    }
};
let proxy = new Proxy(person, handler);
console.log(proxy.fullName); // zhang san
1
2
3
4
5
6
7
8
9
10
11
12
13

set() 方法

set() 方法用于拦截某个属性的赋值操作,接受四个参数:

  1. target:代理对象
  2. key:被设置的属性名
  3. value:新属性值
  4. receiver:最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)

示例:

const person = {
    age: 20,
};
let handler = {
    set(target, key, value){
        if(key === 'age'){
            if(value >150 || value < 0){
                throw new Error('The age seems invalid');
            }
        }
    }
};
let proxy = new Proxy(person, handler);
proxy.age = '-1';
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 4.Proxy 中的 this 指向

一旦 Proxy 代理了 target,target 内部的 this 就指向了 Proxy,而不是 target;有些原生对象的内部属性,只有通过正确的 this 才能拿到,所以 Proxy 无法代理这些原生对象的属性,可以通过 this 绑定 target 来解决这个问题

const target = new Date();
const handler = {
    get(target, key) {
        if (prop === 'getMonth') {
            return target.getMonth.bind(target);
        }
        return Reflect.get(target, key);
    }
};
const proxy = new Proxy(target, handler);

console.log(proxy.getMonth()) // 6
1
2
3
4
5
6
7
8
9
10
11
12

# 6.Proxy 相比 Object.defineProperty 的优势

  1. 支持数组
const arr = [1,2,3];
let proxy = new Proxy(arr, {
    get(target, key, receiver){
        return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver){
        return Reflect.set(target, key, value, receiver);
    }
});
1
2
3
4
5
6
7
8
9

Proxy 不需要对数组的方法进行重载,省去了众多 hack

  1. 针对对象

    在数据劫持这个问题上,Proxy 可以被认为是 Object.defineProperty() 的升级版。外界对某个对象的访问,都必须经过这层拦截。因此它是针对整个对象,而不是对象的某个属性,所以也就不需要对 keys 进行遍历

  2. proxy 有多达13种监听方法